package com.sayice.robotconflict.game.object.group;

import com.sayice.robotconflict.game.Game;
import com.sayice.robotconflict.game.object.Player;
import com.sayice.robotconflict.game.object.Player.State;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelId;

import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 玩家组
 *
 * @author shubing
 */
public class PlayerGroup extends AbstractSet<Player> {
    /**
     * 玩家ID - Player 映射
     */
    private final Map<String, Player> idMap = new ConcurrentHashMap<>(16);
    
    /**
     * ChannelId - Player 映射
     */
    private final Map<ChannelId, Player> channelIdMap = new ConcurrentHashMap<>(16);
    
    /**
     * 当 Player 的 channel 关闭时将其移出
     */
    private final ChannelFutureListener remover = future -> {
        ChannelId channelId = future.channel().id();
        Player player = channelIdMap.get(channelId);
        if (remove(player.id)) {
            State state = player.state.get();
            // 如果状态为匹配中或对局中，则加入到临时退出玩家 map 中
            if (state == State.MATCHING_1 || state == State.MATCHING_3 || state == State.MATCHING_5
                    || state == State.GAMING) {
                Game.TEMP_QUIT_PLAYER_MAP.put(player.id, player);
            }
        }
    };
    
    /**
     * 通过玩家 ID 查找 Player
     *
     * @param playerId 玩家 ID
     */
    public Player find(String playerId) {
        return idMap.get(playerId);
    }
    
    /**
     * 通过 ChannelId 查找 Player
     *
     * @param channelId ChannelId
     */
    public Player find(ChannelId channelId) {
        return channelIdMap.get(channelId);
    }
    
    @Override
    public boolean contains(Object o) {
        if (o instanceof Player) {
            return idMap.containsKey(((Player) o).id);
        }
        return false;
    }
    
    @Override
    public boolean add(Player player) {
        if (idMap.putIfAbsent(player.id, player) == null) {
            channelIdMap.put(player.channelId(), player);
            player.closeFuture().addListener(remover);
            return true;
        }
        return false;
    }
    
    /**
     * 根据玩家ID移除玩家
     *
     * @param id 玩家ID
     * @return 移除成功时为被移除的玩家，否则为null
     */
    public Player removeById(String id) {
        Player player = idMap.remove(id);
        if (player != null) {
            channelIdMap.remove(player.channelId());
            player.closeFuture().removeListener(remover);
        }
        return player;
    }
    
    @Override
    public boolean remove(Object o) {
        Player player = null;
        if (o instanceof String) {
            player = idMap.remove(o);
            if (player != null) {
                channelIdMap.remove(player.channelId());
            }
        } else if (o instanceof ChannelId) {
            player = channelIdMap.remove(o);
            if (player != null) {
                idMap.remove(player.id);
            }
        } else if (o instanceof Player) {
            player = (Player) o;
            player = idMap.remove(player.id);
            if (player != null) {
                channelIdMap.remove(player.channelId());
            }
        }
        if (player == null) {
            return false;
        }
        player.closeFuture().removeListener(remover);
        return true;
    }
    
    @Override
    public void clear() {
        idMap.clear();
        channelIdMap.clear();
    }
    
    @Override
    public int size() {
        return idMap.size();
    }
    
    @Override
    public Iterator<Player> iterator() {
        Iterator<Player> idMapIterator = idMap.values().iterator();
        Iterator<Player> channelIdMapIterator = channelIdMap.values().iterator();
        return new Iterator<Player>() {
            @Override
            public boolean hasNext() {
                return idMapIterator.hasNext();
            }
            
            @Override
            public Player next() {
                idMapIterator.next();
                return channelIdMapIterator.next();
            }
            
            @Override
            public void remove() {
                idMapIterator.remove();
                channelIdMapIterator.remove();
            }
        };
    }
    
    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }
    
    @Override
    public boolean equals(Object o) {
        return this == o;
    }
}
